package com.sinodata.bsm.cicp.util.telnet.pool;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.util.telnet.JtaTelnet;
import com.sinodata.bsm.cicp.util.telnet.Telnet;

/**
 * 
 * <p>
 * Description: Telnet连接池
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-15 PM 3:33:25     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
@Deprecated
public class TelnetPool {

    private static Logger logger = Logger.getLogger(TelnetPool.class);

    private final Map<String, TelnetLock> telnetMaps = new HashMap<String, TelnetLock>();

    private static TelnetPool instance = null;

    private static Map<String, Object> telnetConnectLocks = new HashMap<String, Object>();

    private Object _lock = new Object();

    /**
     * 私有化构造方法
     */
    private TelnetPool() {
        //        Collections.synchronizedMap(telnetMaps);
    }

    /**
     * 单例模式获取TelnetPool实例
     *
     * @return
     */
    public synchronized static TelnetPool getInstance() {
        if (instance == null) {
            instance = new TelnetPool();
        }
        return instance;
    }

    /**
     * 获取一个指向特定IP的Telnet连接  如果连接池中有可用连接则取出一个  如果
     *   没有可用连接则新建一个()
     * @param host
     * @param maxTelnetSize
     * @return
     * @throws Exception
     */
    @Deprecated
    public Telnet getTelnet(String host, int port, String user, String pwd, int maxTelnetSize, String prompt) throws Exception {
        TelnetLock telnetLock = getTelnetLock(host);
        if (telnetLock.getMaxSize() != maxTelnetSize) {
            telnetLock.setMaxSize(maxTelnetSize);
        }
        if (!telnetLock.isConnectable()) {
            logger.error("There is no available connection of Telnet!");
        }
        telnetLock.lock();
        try {
            synchronized (telnetLock.getTelnetList()) {
                if (telnetLock.getTelnetList().size() > 0) {
                    return telnetLock.getTelnetList().removeFirst();
                }
            }
            Object lock = null;
            synchronized (telnetConnectLocks) {
                lock = telnetConnectLocks.get(host);
                if (lock == null) {
                    telnetConnectLocks.put(host, new Object());
                    lock = telnetConnectLocks.get(host);
                }
            }
            synchronized (lock) {
                Telnet jtaTelnet = new JtaTelnet();
                jtaTelnet.connect(host, port);
                jtaTelnet.runLogin(user, pwd, prompt);
                jtaTelnet.setIsValid(true);
                /**
                 * 采集命令应在bash下执行
                 */
                jtaTelnet.runTask("bash");
                /**
                 * 改为英语环境 否则解析shell时会混乱
                 */
                jtaTelnet.runTask("LANG=C;export LANG");

                telnetLock.setConnectable(true);
                return jtaTelnet;
            }
        } catch (Exception e) {
            telnetLock.setConnectable(false);
            logger.error("Failed when create a new telnet connection" + e);
            throw new Exception(e);
        }
    }

    /**
     * 从Map中取数据时加上同步  因为它不是线程安全的
     *
     * @param host
     * @return
     */
    private synchronized TelnetLock getTelnetLock(String host) {
        TelnetLock telnetLock = telnetMaps.get(host);
        if (telnetLock == null) {
            telnetLock = new TelnetLock(host);
            telnetMaps.put(host, telnetLock);
        }
        return telnetLock;
    }

    /**
     * 释放一个指向特定IP主机的telnet连接  释放后的连接放在LinkedList中
     *
     * @param host
     * @param telnet
     */
    public void freeTelnet(String host, Telnet telnet) throws Exception {
        getTelnetLock(host).free(telnet);
    }

    /**
     * 释放一个主机的全部telnet链接,供外部使用，例如重置配置信息
     * 
     * @param host
     * @throws Exception
     */
    public void freeTelnet(String host) throws Exception {
        TelnetLock telnetLock = getTelnetLock(host);
        synchronized (_lock) {
            LinkedList<Telnet> list = telnetLock.getTelnetList();
            for (Telnet telnet : list) {
                telnet.setIsValid(false);
            }
        }
    }

    /**
     *
     * <p>
     * Description: 记录针对特定IP主机的当前telnet连接数和最大连接数并把telnet连接保存在LinkedList集合中
     * </p>
     *
     * @author wangyazhou
     * @version 3.0

     * <p>
     * History:
     *
     * Date                     Author         Version     Description
     * ---------------------------------------------------------------------------------
     * Mar 20, 2011 4:28:27 PM  wangyazhou     3.0         To create
     * </p>
     *
     * @since
     * @see
     */
    class TelnetLock {

        protected String host;

        protected int currentSize = 0;

        protected int maxSize = 10;

        protected boolean connectable = true;

        protected LinkedList<Telnet> telnetList = new LinkedList<Telnet>();

        public TelnetLock(String host) {
            this.host = host;
        }

        /**
         * 新增一个连接时增加当前telnet连接数 超过最大值则等待
         *
         */
        public synchronized void lock() {
            while (currentSize >= maxSize) {
                try {
                    wait();
                } catch (Exception e) {
                    logger.error("Failed to add connections");
                }
            }
            currentSize++;
        }

        /**
         * 释放一个telnet连接
         *
         * @param telnet
         */
        public synchronized void free(Telnet telnet) throws Exception {
            currentSize--;
            if (telnet.getIsValid() == true) {
                telnetList.addLast(telnet);
            } else {
                telnet.disconnect();
            }
            notifyAll();
        }

        public synchronized boolean isConnectable() {
            return connectable || (currentSize < maxSize);
        }

        public synchronized void setConnectable(boolean connectable) {
            this.connectable = connectable;
        }

        public int getMaxSize() {
            return maxSize;
        }

        public void setMaxSize(int maxSize) {
            this.maxSize = maxSize;
        }

        public synchronized LinkedList<Telnet> getTelnetList() {
            return telnetList;
        }

        public synchronized void setTelnetList(LinkedList<Telnet> telnetList) {
            this.telnetList = telnetList;
        }

    }

}